Program Status Register
&
conditional execution

 

Register 15:

R15 is built up as follows:
  Bit  31  30  29  28  27  26  25------------2  1  0

       N   Z   C   V   I   F   Program Counter  S1 S0
The flags mean:
  N  Negative        Set if result is negative
  Z  Zero            Set if result is zero
  C  Carry           Set if carry occurs
  O  Overflow        Set if overflow occurs
  I  IRQ             Interrupt disable
  F  FIQ             Fast Interrupt disable
  
  S1 and S0 are processor mode flags:
  
           S1   S0   Mode
           0    0    USR - User mode
           0    1    FIQ - Fast Interrupt mode
           1    0    IRQ - Interrupt mode
           1    1    SVC - Supervisor mode

When R15 is used as the first operand in an instruction, only the Program Counter part of it is available. Thus, the following instruction will copy PC out to a register and add 256 to it:
  ADD    R0, R15, #256
(R15 and PC mean the same thing to the BASIC assembler)

When R15 is used as the second operand, all 32 bits are accessible: the Program Counter, the flags, and the status. The following code segment will identify the current processor mode:

   MOV     R0, #3          ; Load a bit mask (%11) into R0
   AND     R0, R0, PC      ; AND R15 into R0, to get the mode status
   CMP     R0, #3          ; Compare mode with '3' (SVC)
   BEQ     svc             ; If SVC mode, branch to 'svc'
   CMP     R0, #2          ; Compare mode with '2' (IRQ)
   BEQ     irq             ; If IRQ mode, branch to 'irq'
   CMP     R0, #1          ; Compare mode with '1' (FIQ)
   BEQ     fiq             ; If FIQ mode, branch to 'fiq'
   CMP     R0, #0          ; Compare mode with '0' (USR)
   BEQ     usr             ; If USR mode, branch to 'usr'
Download example: currmode.basic

Changing processor status:

In order to change the processor mode, or indeed any of the flags, we need to EOR the desired flag with the status flags,
  new_state = old_state EOR (1 << 28) could be pseudocode for changing the state of the oVerflow flag. But we cannot do a simple EORS operation as the pipeline would cause the following two instructions to be skipped.
But don't worry. The instruction TEQ does a pretend EOR (the results are not stored anywhere). Combine this with the P suffix, which writes bits 0, 1, and 26 to 31 of the result directly to bits 0, 1, and 26 to 31 of R15 giving you an easy way to change the flags:   TEQP   R15, bit_mask

You can only change a flag if you are in a processor mode which allows you to set that flag.

This can be expanded to change processor mode. For example, to enter SVC mode you would:

   MOV     R6, PC          ; Store original state of PC in R6
   ORR     R7, R6, #3      ; Set SVC mode
   TEQP    R7, #0          ; Write mode flags (in R7) to PC
And to return to the original mode:
   TEQP    R6, #0          ; Write previous mode flags (in R6) to PC
Download example: setmode.basic

After changing the mode, you should perform a null operation to allow the registers to settle. Something like MOV R0, R0 should be okay. The use of NV suffixed instructions has been deprecated.

 

 

Conditional execution:

A very special feature of the ARM processor is its conditional execution. We are not talking your basic Branch if Carry Set, the ARM takes this a logical stage further to mean XXX if carry set - where XXX is just about anything.

By way of example, here is a list of branch instructions understood by the Intel 8086 processor:

  JA    Jump if Above
  JAE   Jump if Above or Equal
  JB    Jump if Below
  JBE   Jump if Below or Equal
  JC    Jump if Carry
  JCXZ  Jump if CX Zero (CX is a register that can be used for loop counts)
  JE    Jump if Equal
  JG    Jump if Greater than
  JGE   Jump if Greater than or Equal
  JL    Jump if Less than
  JLE   Jump if Less Than or Equal
  JMP   JuMP
  JNA   Jump if Not Above
  JNAE  Jump if Not Above or Equal
  JNB   Jump if Not Below
  JNBE  Jump if Not Below or Equal
  JNC   Jump if No Carry
  JNE   Jump if Not Equal
  JNG   Jump if Not Greater than
  JNGE  Jump if Not Greater than or Equal
  JNL   Jump if Not Less than
  JNLE  Jump if Not Less than or Equal
  JNO   Jump if Not Overflow
  JNP   Jump if Not Parity
  JNS   Jump if Not Sign
  JNZ   Jump if Not Zero
  JO    Jump if Overflow
  JP    Jump if Parity
  JPE   Jump if Parity Even
  JPO   Jump if Parity Odd
  JS    Jump if Sign
  JZ    Jump if Zero

And the 80386 added:
  JECXZ Jump if ECX Zero
And by contrast, the ARM processor offers a whopping...uh...
  B     Branch
  BL    Branch with Link
But the ARM is not limited by this seemingly inflexible approach due to conditional execution which offers you:
  BEQ   Branch if EQual
  BNE   Branch if Not Equal
  BVS   Branch if oVerflow Set
  BVC   Branch if oVerflow Clear
  BHI   Branch if HIgher
  BLS   Branch if Lower or the Same
  BPL   Branch if PLus
  BMI   Branch if MInus
  BCS   Branch if Carry Set
  BCC   Branch if Carry Clear
  BGE   Branch if Greater than or Equal
  BGT   Branch if Greater Than
  BLE   Branch if Less than or Equal
  BLT   Branch if Less Than

  BLEQ  Branch with Link if EQual
  ....
  BLLT  Branch with Link if Less Than
There are two more codes, The crunch comes, however, when you realise that all of the Bxx instructions are actually the same instruction. Then you will think, if you can do all that to a branch instruction, can it be done to, say, a register load instruction?
The answer is yes.

 

 

Here follows a list of available conditional codes:

EQ : Equal
If the Z flag is set after a comparison.

NE : Not Equal
If the Z flag is clear after a comparison.

VS : Overflow Set
If the V flag is set after an arithmetical operation, the result of which will not fit into a 32bit destination register.

VC : Overflow Clear
If the V flag is clear, the reverse of VS.

HI : Higher Than (unsigned)
If after a comparison the C flag is set AND the Z flag is clear.

LS : Lower Than or Same (unsigned)
If after a comparison the C flag is clear OR the Z flag is set.

PL : Plus
If the N flag is clear after an arithmetical operation. For the purposes of defining 'plus', zero is positive because it isn't negative...

MI : Minus
If the N flag is set after an arithmetical operation.

CS : Carry Set
Set if the C flag is set after an arithmetical operation OR a shift operation, the result of which cannot be represented in 32bits. You can think of the C flag as the 33rd bit of the result.

CC : Carry Clear
The reverse of CS.

GT : Greater Than or Equal (signed)
If after a comparison...
the N flag is set AND the V flag is set
or...
the N flag is clear AND the V flag is clear.

GT : Greater Than (signed)
If after a comparison...
the N flag is set AND the V flag is set
or...
the N flag is clear AND the V flag is clear
and...
the Z flag is clear.

LE : Less Than or Equal To (signed)
If after a comparison...
the N flag is set AND the V flag is clear
or...
the N flag is clear AND the V flag is set
and...
the Z flag is set.

LT : Less Than (signed)
If after a comparison...
the N flag is set AND the V flag is clear
or...
the N flag is clear AND the V flag is set.

AL : Always
The default condition, so does not need to be explicity stated.

NV : Never
Not particularly useful, it states that the instruction should never be executed. A kind of Poor Mans' NOP.
NV was included for completeness (as the reverse of AL), but you should not use it in your own code.
There is a final conditional code which works in the reverse way. S, when applied to an instruction, causes the status flags to be updated. This does not happen automatically - except for those instructions whose purpose is to set the status. For example:
  ADD     R0, R0, R1

  ADDS    R0, R0, R1

  ADDEQS  R0, R0, R1
The first example shows us a basic addition (adding the value of R1 to R0) which does not affect the status registers.

The second example shows us the same addition, only this time it will cause the status registers to be updated.

The last example shows us the addition again, updating the status registers. The difference here is that it is a conditional instruction. It will only be executed if the result of a previous operation was EQual (if the Z flag is set).

 

 

Here is an example of conditional execution at work. You want to compare register zero with the contents of something stored in register ten. If not equal to R10, then call a software interrupt, increment and branch back to do it again. Otherwise clear R10 and return to a calling piece of code (whose address is stored in R14).

  \ An example of conditional execution

  .loop                           ; Mark the loop start position
  CMP     R0, R10                 ; Compare R0 with R10
  SWINE   &40017                  ; Not equal: Call SWI &40017
  ADDNE   R0, R0, #1              ;            Add 1 to R0
  BNE     loop                    ;            Branch to 'loop'
  MOV     R10, #0                 ; Equal    : Set R10 to zero
  LDMFD   R13!, {R0-R12,PC}       ;            Return to caller
Notes:

 

 


Return to assembler index
Copyright © 2000 Richard Murray